//
// Copyright (c) 2004 K. Wilkins
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from
// the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would be
//    appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
//    be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

//////////////////////////////////////////////////////////////////////////////
//                       Handy - An Atari Lynx Emulator                     //
//                          Copyright (c) 1996,1997                         //
//                                 K. Wilkins                               //
//////////////////////////////////////////////////////////////////////////////
// 65C02 Macro definitions                                                  //
//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// This file contains all of the required address mode and operand          //
// macro definitions for the 65C02 emulation                                //
//                                                                          //
//    K. Wilkins                                                            //
// August 1997                                                              //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////
// Revision History:                                                        //
// -----------------                                                        //
//                                                                          //
// 01Aug1997 KW Document header added & class documented.                   //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

//
// Addressing mode decoding
//

#define xIMMEDIATE()            {mOperand=mPC;mPC++;}
#define xABSOLUTE()             {mOperand=CPU_PEEKW(mPC);mPC+=2;}
#define xZEROPAGE()             {mOperand=CPU_PEEK(mPC);mPC++;}
#define xZEROPAGE_X()           {mOperand=CPU_PEEK(mPC)+mX;mPC++;mOperand&=0xff;}
#define xZEROPAGE_Y()           {mOperand=CPU_PEEK(mPC)+mY;mPC++;mOperand&=0xff;}
#define xABSOLUTE_X()           {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mX;mOperand&=0xffff;}
#define xABSOLUTE_Y()           {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mY;mOperand&=0xffff;}
#define xINDIRECT_ABSOLUTE_X()  {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand+=mX;mOperand&=0xffff;mOperand=CPU_PEEKW(mOperand);}
#define xRELATIVE()             {mOperand=CPU_PEEK(mPC);mPC++;mOperand=(mPC+mOperand)&0xffff;}
#define xINDIRECT_X()           {mOperand=CPU_PEEK(mPC);mPC++;mOperand=mOperand+mX;mOperand&=0x00ff;mOperand=CPU_PEEKW(mOperand);}
#define xINDIRECT_Y()           {mOperand=CPU_PEEK(mPC);mPC++;mOperand=CPU_PEEKW(mOperand);mOperand=mOperand+mY;mOperand&=0xffff;}
#define xINDIRECT_ABSOLUTE()    {mOperand=CPU_PEEKW(mPC);mPC+=2;mOperand=CPU_PEEKW(mOperand);}
#define xINDIRECT()             {mOperand=CPU_PEEK(mPC);mPC++;mOperand=CPU_PEEKW(mOperand);}

//
// Helper Macros
//
//#define SET_Z(m)              { mZ=(m)?false:true; }
//#define SET_N(m)              { mN=(m&0x80)?true:false; }
//#define SET_NZ(m)             SET_Z(m) SET_N(m)
#define SET_Z(m)                { mZ=!(m); }
#define SET_N(m)                { mN=(m)&0x80; }
#define SET_NZ(m)               { mZ=!(m); mN=(m)&0x80; }
#define PULL(m)                 { mSP++; mSP&=0xff; m=CPU_PEEK(mSP+0x0100); }
#define PUSH(m)                 { CPU_POKE(0x0100+mSP,m); mSP--; mSP&=0xff; }
//
// Opcode execution
//

/*
#define xADC()\
{\
    UBYTE   value=CPU_PEEK(mOperand);\
    UBYTE   oldA=mA;\
    if(!mD)\
    {\
        SWORD sum=(SWORD)((SBYTE)mA)+(SWORD)((SBYTE)value)+(mC?1:0);\
        mV=((sum > 127) || (sum < -128));\
        sum=(SWORD)mA + (SWORD)value + (mC?1:0);\
        mA=(UBYTE)sum;\
        mC=(sum>0xff);\
        SET_NZ(mA);\
    }\
    else\
    {\
        SWORD sum=mBCDTable[0][mA]+mBCDTable[0][value]+(mC?1:0);\
        mC=(sum > 99);\
        mA=mBCDTable[1][sum & 0xff];\
        SET_NZ(mA);\
        mV=((oldA^mA)&0x80) && ((mA^value)&0x80);\
    }\
}
*/

#define xADC()\
{\
    int value=CPU_PEEK(mOperand);\
    if(mD)\
    {\
        int c = mC?1:0;\
        int lo = (mA & 0x0f) + (value & 0x0f) + c;\
        int hi = (mA & 0xf0) + (value & 0xf0);\
        mV=0;\
        mC=0;\
        if (lo > 0x09)\
        {\
            hi += 0x10;\
            lo += 0x06;\
        }\
        if (~(mA^value) & (mA^hi) & 0x80) mV=1;\
        if (hi > 0x90) hi += 0x60;\
        if (hi & 0xff00) mC=1;\
        mA = (lo & 0x0f) + (hi & 0xf0);\
    }\
    else\
    {\
        int c = mC?1:0;\
        int sum = mA + value + c;\
        mV=0;\
        mC=0;\
        if (~(mA^value) & (mA^sum) & 0x80) mV=1;\
        if (sum & 0xff00) mC=1;\
        mA = (UBYTE) sum;\
    }\
    SET_NZ(mA)\
}

#define xAND()\
{\
    mA&=CPU_PEEK(mOperand);\
    SET_NZ(mA);\
}

#define xASL()\
{\
    int value=CPU_PEEK(mOperand);\
    mC=value&0x80;\
    value<<=1;\
    value&=0xff;\
    SET_NZ(value);\
    CPU_POKE(mOperand,value);\
}

#define xASLA()\
{\
    mC=mA&0x80;\
    mA<<=1;\
    mA&=0xff;\
    SET_NZ(mA);\
}

#define xBCC()\
{\
    if(!mC)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xBCS()\
{\
    if(mC)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xBEQ()\
{\
    if(mZ)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xBIT()\
{\
    int value=CPU_PEEK(mOperand);\
    SET_Z(mA&value);\
\
    if(mOpcode!=0x89)\
    {\
        mN=value&0x80;\
        mV=value&0x40;\
    }\
}

/*
//
// DONT USE THIS VERSION OF BIT, IT BREAKS CALGAMES TITLE SCREEN !!!!
//
#define xBIT()\
{\
    int value=CPU_PEEK(mOperand);\
    SET_Z(mA&value);\
\
    mN=value&0x80;\
    mV=value&0x40;\
}
*/

#define xBMI()\
{\
    if(mN)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xBNE()\
{\
    if(!mZ)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xBPL()\
{\
    if(!mN)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xBRA()\
{\
    int offset=(signed char)CPU_PEEK(mPC);\
    mPC++;\
    mPC+=offset;\
    mPC&=0xffff;\
}

/*
#define xBRK()\
{\
    mPC++;\
    PUSH(mPC>>8);\
    PUSH(mPC&0xff);\
    PUSH(PS()|0x10);\
\
    mD=FALSE;\
    mI=TRUE;\
\
    mPC=CPU_PEEKW(IRQ_VECTOR);\
}
*/

#define xBRK()\
{\
    mPC++;\
    PUSH(mPC>>8);\
    PUSH(mPC&0xff);\
    PUSH(PS()|0x10);\
\
    mD=FALSE;\
    mI=TRUE;\
\
    mPC=CPU_PEEKW(IRQ_VECTOR);\
}
// KW 4/11/98 B flag needed to be set IN the stack status word = 0x10.

#define xBVC()\
{\
    if(!mV)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xBVS()\
{\
    if(mV)\
    {\
        int offset=(signed char)CPU_PEEK(mPC);\
        mPC++;\
        mPC+=offset;\
        mPC&=0xffff;\
    }\
    else\
    {\
        mPC++;\
        mPC&=0xffff;\
    }\
}

#define xCLC()\
{\
    mC=FALSE;\
}

#define xCLD()\
{\
    mD=FALSE;\
}

#define xCLI()\
{\
    mI=FALSE;\
}

#define xCLV()\
{\
    mV=FALSE;\
}

//
// Alternate CMP code
//
/*
#define xCMP()\
{\
    UBYTE value=CPU_PEEK(mOperand);\
    if(mA+0x100-value>0xff) mC=TRUE; else mC=FALSE;\
    value=mA+0x100-value;\
    mZ=!value;\
    mN=value&0x0080;\
}

#define xCPX()\
{\
    UBYTE value=CPU_PEEK(mOperand);\
    if(mX+0x100-value>0xff) mC=TRUE; else mC=FALSE;\
    value=mX+0x100-value;\
    mZ=!value;\
    mN=value&0x0080;\
}

#define xCPY()\
{\
    UBYTE value=CPU_PEEK(mOperand);\
    if(mY+0x100-value>0xff) mC=TRUE; else mC=FALSE;\
    value=mY+0x100-value;\
    mZ=!value;\
    mN=value&0x0080;\
}

#define xCMP()\
{\
    UWORD value=(UWORD)mA-CPU_PEEK(mOperand);\
    SET_NZ(value);\
    mC=!(value&0x0100);\
}
*/
#define xCMP()\
{\
    int value=CPU_PEEK(mOperand);\
    mC=0;\
    if (mA >= value) mC=1;\
    SET_NZ((UBYTE)(mA - value))\
}

/*
#define xCPX()\
{\
    UWORD value=(UWORD)mX-CPU_PEEK(mOperand);\
    SET_NZ(value);\
    mC=!(value&0x0100);\
}
*/

#define xCPX()\
{\
    int value=CPU_PEEK(mOperand);\
    mC=0;\
    if (mX >= value) mC=1;\
    SET_NZ((UBYTE)(mX - value))\
}

/*
#define xCPY()\
{\
    UWORD value=(UWORD)mY-CPU_PEEK(mOperand);\
    SET_NZ(value);\
    mC=!(value&0x0100);\
}
*/

#define xCPY()\
{\
    int value=CPU_PEEK(mOperand);\
    mC=0;\
    if (mY >= value) mC=1;\
    SET_NZ((UBYTE)(mY - value))\
}

#define xDEC()\
{\
    int value=CPU_PEEK(mOperand)-1;\
    value&=0xff;\
    CPU_POKE(mOperand,value);\
    SET_NZ(value);\
}

#define xDECA()\
{\
    mA--;\
    mA&=0xff;\
    SET_NZ(mA);\
}

#define xDEX()\
{\
    mX--;\
    mX&=0xff;\
    SET_NZ(mX);\
}

#define xDEY()\
{\
    mY--;\
    mY&=0xff;\
    SET_NZ(mY);\
}

#define xEOR()\
{\
    mA^=CPU_PEEK(mOperand);\
    SET_NZ(mA);\
}

#define xINC()\
{\
    int value=CPU_PEEK(mOperand)+1;\
    value&=0xff;\
    CPU_POKE(mOperand,value);\
    SET_NZ(value);\
}

#define xINCA()\
{\
    mA++;\
    mA&=0xff;\
    SET_NZ(mA);\
}

#define xINX()\
{\
    mX++;\
    mX&=0xff;\
    SET_NZ(mX);\
}

#define xINY()\
{\
    mY++;\
    mY&=0xff;\
    SET_NZ(mY);\
}

#define xJMP()\
{\
    mPC=mOperand;\
}

#define xJSR()\
{\
    PUSH((mPC-1)>>8);\
    PUSH((mPC-1)&0xff);\
    mPC=mOperand;\
}

#define xLDA()\
{\
    mA=CPU_PEEK(mOperand);\
    SET_NZ(mA);\
}

#define xLDX()\
{\
    mX=CPU_PEEK(mOperand);\
    SET_NZ(mX);\
}

#define xLDY()\
{\
    mY=CPU_PEEK(mOperand);\
    SET_NZ(mY);\
}

#define xLSR()\
{\
    int value=CPU_PEEK(mOperand);\
    mC=value&0x01;\
    value=(value>>1)&0x7f;\
    CPU_POKE(mOperand,value);\
    SET_NZ(value);\
}

#define xLSRA()\
{\
    mC=mA&0x01;\
    mA=(mA>>1)&0x7f;\
    SET_NZ(mA);\
}

#define xNOP()\
{\
}

#define xORA()\
{\
    mA|=CPU_PEEK(mOperand);\
    SET_NZ(mA);\
}

#define xPHA()\
{\
    PUSH(mA);\
}

#define xPHP()\
{\
    PUSH(PS());\
}

#define xPHX()\
{\
    PUSH(mX);\
}

#define xPHY()\
{\
    PUSH(mY);\
}

#define xPLA()\
{\
    PULL(mA);\
    SET_NZ(mA);\
}

#define xPLP()\
{\
    int P;\
    PULL(P);\
    PS(P);\
}

#define xPLX()\
{\
    PULL(mX);\
    SET_NZ(mX);\
}

#define xPLY()\
{\
    PULL(mY);\
    SET_NZ(mY);\
}

#define xROL()\
{\
    int value=CPU_PEEK(mOperand);\
    int oldC=mC;\
    mC=value&0x80;\
    value=(value<<1)|(oldC?1:0);\
    value&=0xff;\
    CPU_POKE(mOperand,value);\
    SET_NZ(value);\
}

#define xROLA()\
{\
    int oldC=mC;\
    mC=mA&0x80;\
    mA=(mA<<1)|(oldC?1:0);\
    mA&=0xff;\
    SET_NZ(mA);\
}

#define xROR()\
{\
    int value=CPU_PEEK(mOperand);\
    int oldC=mC;\
    mC=value&0x01;\
    value=((value>>1)&0x7f)|(oldC?0x80:0x00);\
    value&=0xff;\
    CPU_POKE(mOperand,value);\
    SET_NZ(value);\
}

#define xRORA()\
{\
    int oldC=mC;\
    mC=mA&0x01;\
    mA=((mA>>1)&0x7f)|(oldC?0x80:0x00);\
    mA&=0xff;\
    SET_NZ(mA);\
}

#define xRTI()\
{\
    int tmp;\
    PULL(tmp);\
    PS(tmp);\
    PULL(mPC);\
    PULL(tmp);\
    mPC|=tmp<<8;\
}

#define xRTS()\
{\
    int tmp;\
    PULL(mPC);\
    PULL(tmp);\
    mPC|=tmp<<8;\
    mPC++;\
}

/*
#define xSBC()\
{\
    UBYTE oldA=mA;\
    if(!mD)\
    {\
        UBYTE value=~(CPU_PEEK(mOperand));\
        SWORD difference=(SWORD)((SBYTE)mA)+(SWORD)((SBYTE)value)+(mC?1:0);\
        mV=((difference>127)||(difference<-128));\
        difference=((SWORD)mA)+((SWORD)value)+ (mC?1:0);\
        mA=(UBYTE)difference;\
        mC=(difference>0xff);\
        SET_NZ(mA);\
    }\
    else\
  {\
        UBYTE value=CPU_PEEK(mOperand);\
        SWORD difference=mBCDTable[0][mA]-mBCDTable[0][value]-(mC?0:1);\
        if(difference<0) difference+=100;\
        mA=mBCDTable[1][difference];\
        mC=(oldA>=(value+(mC?0:1)));\
        mV=((oldA^mA)&0x80)&&((mA^value)&0x80);\
        SET_NZ(mA);\
    }\
}
*/

#define xSBC()\
{\
    int value=CPU_PEEK(mOperand);\
    if (mD)\
    {\
        int c = mC?0:1;\
        int sum = mA - value - c;\
        int lo = (mA & 0x0f) - (value & 0x0f) - c;\
        int hi = (mA & 0xf0) - (value & 0xf0);\
        mV=0;\
        mC=0;\
        if ((mA^value) & (mA^sum) & 0x80) mV=1;\
        if (lo & 0xf0) lo -= 6;\
        if (lo & 0x80) hi -= 0x10;\
        if (hi & 0x0f00) hi -= 0x60;\
        if ((sum & 0xff00) == 0) mC=1;\
        mA = (lo & 0x0f) + (hi & 0xf0);\
    }\
    else\
    {\
        int c = mC?0:1;\
        int sum = mA - value - c;\
        mV=0;\
        mC=0;\
        if ((mA^value) & (mA^sum) & 0x80) mV=1;\
        if ((sum & 0xff00) == 0) mC=1;\
        mA = (UBYTE) sum;\
    }\
    SET_NZ(mA)\
}

#define xSEC()\
{\
    mC=true;\
}

#define xSED()\
{\
    mD=true;\
}

#define xSEI()\
{\
    mI=true;\
}

#define xSTA()\
{\
    CPU_POKE(mOperand,mA);\
}

#define xSTP()\
{\
    gSystemCPUSleep=TRUE;\
}

#define xSTX()\
{\
    CPU_POKE(mOperand,mX);\
}

#define xSTY()\
{\
    CPU_POKE(mOperand,mY);\
}

#define xSTZ()\
{\
    CPU_POKE(mOperand,0);\
}

#define xTAX()\
{\
    mX=mA;\
    SET_NZ(mX);\
}

#define xTAY()\
{\
    mY=mA;\
    SET_NZ(mY);\
}

#define xTRB()\
{\
    int value=CPU_PEEK(mOperand);\
    SET_Z(mA&value);\
    value=value&(mA^0xff);\
    CPU_POKE(mOperand,value);\
}
//
// THE COMMENTED OUT CODE IS DERIVED FROM THE MAME 65C02 MODEL AND
// LOOKS TO BE INCORRECT i.e When plugged into Handy things stop working
//
/*
#define xTRB()\
{\
    int value=CPU_PEEK(mOperand);\
    value &= ~mA;\
    SET_NZ(value);\
    CPU_POKE(mOperand,value);\
}
*/

#define xTSB()\
{\
    int value=CPU_PEEK(mOperand);\
    SET_Z(mA&value);\
    value=value|mA;\
    CPU_POKE(mOperand,value);\
}
//
// THE COMMENTED OUT CODE IS DERIVED FROM THE MAME 65C02 MODEL AND
// LOOKS TO BE INCORRECT i.e When plugged into Handy things stop working
//
/*
#define xTSB()\
{\
    int value=CPU_PEEK(mOperand);\
    value |= mA;\
    SET_NZ(value);\
    CPU_POKE(mOperand,value);\
}
*/

#define xTSX()\
{\
    mX=mSP;\
    SET_NZ(mX);\
}

#define xTXA()\
{\
    mA=mX;\
    SET_NZ(mA);\
}

#define xTXS()\
{\
    mSP=mX;\
}

#define xTYA()\
{\
    mA=mY;\
    SET_NZ(mA);\
}

#define xWAI()\
{\
    gSystemCPUSleep=TRUE;\
}

